package service
{
	import common.SharedObjectUtil;
	
	import domain.BuildResult;
	import domain.Project;
	
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	
	import mx.collections.ArrayCollection;
	
	[Bindable]
	public class BambooService
	{
		public static const ACTION_LOGIN:String = "login";
		public static const ACTION_LOGOUT:String = "logout";
		public static const ACTION_LIST_ALL_PROJECTS:String = "listProjectNames";
		public static const ACTION_LIST_ALL_BUILDS:String = "listBuildNames";
		public static const ACTION_LATEST_PROJECT_RESULTS:String = "getLatestBuildResultsForProject";
		public static const ACTION_LATEST_BUILD_RESULTS:String = "getLatestBuildResults";

		private static const ACTION_POSTFIX:String = ".action?";
		private static const restApi:String = "api/rest/";
		
		private var sharedObject:SharedObjectUtil;
		
		public function BambooService(){
			sharedObject = SharedObjectUtil.getInstance();
		}

		public function getAllProjects( callback:Function ):void {
			new GetAllProjectsRequest( sharedObject.username, sharedObject.password, this, callback ).send();
		}
		public function getLatestProjectResults( projects:ArrayCollection, callback:Function=null ):void {
			new GetLatestBuildResultsRequest( sharedObject.username, sharedObject.password, projects, this, callback ).send();
		}
		
		public function loadLatestProjectResults( auth:String, project:Project, callback:Function ):void {
			sendRequest( 
					function(event:Event):void {
						var xml:XML = new XML(event.currentTarget.data);
						if( xml.name()=="errors" ){
			        		throw new Error("error requesting latest build results for project["+project.key+"]");
			        	}
			        	project.latestBuildResults = parseLatestProjectResults( xml );
						callback( project );
					},
					ACTION_LATEST_PROJECT_RESULTS,
					"auth="+auth+"&projectKey="+project.key
				);
		} 
		
		public function requestAuthToken(username:String, password:String, callback:Function, failureCallback:Function=null):void {
			trace("requesting auth token...");
			sendRequest( 
					function(event:Event):void { 
						try {
							var xml:XML = new XML(event.currentTarget.data);
							if( xml.name()=="errors" ){
								throw new Error(xml.error);
				        	}
							trace("got auth token");
				        	callback( xml.auth );
						} catch (e:Error){
							if( failureCallback != null ){
								failureCallback( new Error("authentication failed ["+e.message+"]") );
							}
						}
					},
					ACTION_LOGIN, 
					"username="+username+"&password="+password,
					failureCallback
				);
		}
		
		public function releaseAuthToken( auth:String, callback:Function=null ):void {
        	trace("releasing auth token...");
			sendRequest( 
					function( event:Event ):void {
						var xml:XML = new XML(event.currentTarget.data);
						if( xml.name()=="errors" ){
			        		throw new Error("error releasing auth token");
			        	}
			        	if( callback != null ){
							callback();
			        	}
					}, 
					ACTION_LOGOUT, 
					"auth="+auth 
				);
		}
		public function loadAllProjects( auth:String, callback:Function ):void {
        	trace("requesting project list");
			sendRequest( 
					function( event:Event ):void {
						var xml:XML = new XML(event.currentTarget.data);
						if( xml.name()=="errors" ){
			        		throw new Error("error loading all projects");
			        	}
						callback( parseProjectList( xml ) );
					}, 
					ACTION_LIST_ALL_PROJECTS, 
					"auth="+auth 
				);
		}
		private function parseProjectList(node:XML):ArrayCollection {
        	trace("recieved project list");
        	var projects:ArrayCollection = new ArrayCollection();

    		for each( var xml:XML in node.project ){
    			projects.addItem( new Project(xml) );
    		}
    		
    		return projects;
        }
        
		public function sendRequest(callback:Function, action:String, params:String, failureCallback:Function=null):void { 
			var urlRequest:URLRequest = new URLRequest(sharedObject.bambooUrl+restApi+action+ACTION_POSTFIX+params);
//			trace( "sending request to bamboo server: "+ urlRequest.url );
			var loader:URLLoader = new URLLoader();
			
			loader.addEventListener(Event.COMPLETE, callback );
			loader.addEventListener(IOErrorEvent.IO_ERROR, function():void { 
					if( failureCallback != null ){
						failureCallback( new Error("io error, check server url ["+urlRequest.url+"]") );
					}
				});	
			loader.load(urlRequest);	
		}

        private function parseLatestProjectResults(node:XML):ArrayCollection {
        	var buildResults:ArrayCollection = new ArrayCollection();
        	
    		for each( var xml:XML in node.build ){
    			buildResults.addItem( new BuildResult(xml) );
    		}
    		
    		return buildResults;
        }


	}
}
